import { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import md5 from 'md5'
import { serviceContext } from '../../../context'

interface IRequestInfo {
  url: string
  startTime: number
}
const requestMap: Record<string, IRequestInfo> = {}

export function interceptorLog(http: AxiosInstance): void {
  http.interceptors.request.use((config: AxiosRequestConfig) => {
    const requestUrl = /^http.*/g.test(config.url || '') ? config.url || '' : `${config.baseURL}/${(config.url || '').replace(/^\//g, '')}`
    serviceContext.get().logger.debug({
      module: 'Http',
      method: 'HttpRequest',
      message: `URL = ${config.url}, param = `,
      data: config.data
    })

    const key = generateKey(config)
    requestMap[key] = {
      url: requestUrl,
      startTime: Date.now()
    }
    return config
  })

  http.interceptors.response.use(
    (response: AxiosResponse) => {
      printLog(response.config, response.data)
      return response
    },
    (error: AxiosError) => {
      printLog(error.config, undefined, error)
      return Promise.reject(error)
    }
  )
}

function generateKey(config: AxiosRequestConfig) {
  const url = /^http.*/g.test(config.url || '') ? config.url : `${config.baseURL}${config.url}`
  const params = typeof config.params === 'string' ? config.params : JSON.stringify(config.params)
  const data = typeof config.data === 'string' ? config.data : JSON.stringify(config.data)

  return md5(`${config.method}|${url}|${params}|${data}`)
}

function printLog(config: AxiosRequestConfig, data?: unknown, error?: AxiosError) {
  if (!config) {
    return
  }
  const key = generateKey(config)
  const requestData = requestMap[key]
  const costTime = Date.now() - requestData.startTime
  if (data) {
    serviceContext.get().logger.debug({
      module: 'Http',
      method: 'HttpResponse',
      message: `request succeed => URL = ${requestData.url}, time: ${costTime}ms, response: `,
      data: data
    })
  } else {
    serviceContext.get().logger.debug({
      module: 'Http',
      method: 'HttpResponse',
      message: `request failed => URL = ${requestData.url}, time: ${costTime}ms, error: `,
      data: error
    })
  }
}
